package cn.xorange.commons.datasource.service;

import cn.xorange.commons.datasource.constants.DataDefaultConstants;
import cn.xorange.commons.datasource.constants.DriverType;
import cn.xorange.commons.datasource.constants.YmlConstants;
import cn.xorange.commons.utils.lang.ObjectUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class DataSourceService {

    private String primary;
    private Map<Object,Object> dataSources;
    private Map<String,String> dataSourceKeys;
    private Map<String,Object> pubDruidConfig;

    public String getPrimary() {
        return primary;
    }
    public Map<String,String> getDataSourceKeys(){
        return dataSourceKeys;
    }

    private void setPubDruidConfig(Map<String, Object> pubDruidConfig) {
        Map<String,Object> newMap = new HashMap<>();
        for (Map.Entry<String,Object> entry : DataDefaultConstants.druidConfig().entrySet()) {
            String key = entry.getKey();
            if (!YmlConstants.NAME.equals(key) &&!YmlConstants.PASSWORD.equals(key)){
                newMap.put(key, entry.getValue() );
            }
        }
        if (!pubDruidConfig.isEmpty()){
            for (Map.Entry<String,Object> entry : pubDruidConfig.entrySet()) {
                String key = entry.getKey();
                if (!YmlConstants.NAME.equals(key) &&!YmlConstants.PASSWORD.equals(key)){
                    newMap.put(key,entry.getValue());
                }
            }
        }
        this.pubDruidConfig = newMap;
    }
    private void setPrimary(Map<String,Object> originalDS,Map<String,Map<String,Object>> dataSource,Map<String,Object> defaultDataSourceConfig){
        if (!originalDS.isEmpty()){
            this.primary = YmlConstants.ORIGINAL;
        }else if(dataSource.size()==1){
            this.primary = YmlConstants.SYS;
        }else {
            if (defaultDataSourceConfig.containsKey(YmlConstants.MASTER)){
                this.primary = ObjectUtils.toString(defaultDataSourceConfig.get(YmlConstants.MASTER));
            }else {
                for (Map.Entry<String,Map<String,Object>> entry : dataSource.entrySet()) {
                    String key = entry.getKey();
                    if(!YmlConstants.ORIGINAL.equals(key) &&!YmlConstants.SYS.equals(key)){
                        this.primary = key;
                        break;
                    }
                }
            }
        }
    }

    public Map<Object, Object> getDataSources() {
        return dataSources;
    }
    public void setDataSource (Map<String,Object> defaultDataSourceConfig){
        //获取默认公共Druid配置
        this.setPubDruidConfig((Map<String,Object>)defaultDataSourceConfig.get(YmlConstants.DRUID));

        ///////////////////格式化并且装载DataSource//////////////////////////////////////
        //获取原生态写法配置数据库（单数据库）
        Map<String,Map<String,Object>> dataSource = new HashMap<>();
        Map<String,Object> originalDS = this.getOriginalDataSource(defaultDataSourceConfig,this.pubDruidConfig);
        if (!originalDS.isEmpty()) {
            dataSource.put(YmlConstants.ORIGINAL,originalDS);
            dataSource.put("sys",this.getDSConfig(defaultDataSourceConfig,"sys",this.pubDruidConfig));
        }else {
            ///提取数据库连接支持多数据源
            // 使用datasource下写入数据库标识在写url格式
            //  datasource：
            //    myDb:
            //      url:
            for (Map.Entry<String,Object> entry : defaultDataSourceConfig.entrySet()) {
                String key = entry.getKey();
                if(ObjectUtils.isMap(defaultDataSourceConfig.get(key))&&
                        !YmlConstants.DRUID.equals(key)&&
                        !"global".equals(key)
                ){
                    dataSource.put(key,this.getDSConfig(defaultDataSourceConfig,key,this.pubDruidConfig));
                }
            }
        }
        /////////////////////////////////////////////////////////////////////////////////

        /////////////配置primary/////////////////////////////////////
        this.setPrimary(originalDS,dataSource,defaultDataSourceConfig);

        ////////配置KeysMap和带事务的数据源///////////////////////////////////////////
        TransactionChooseFactory transactionChooseFactory = new TransactionChooseFactory();
        Map<String,String> keysMap = new HashMap<>();
        Map<Object,Object> myDS = new HashMap<>();
        for (Map.Entry<String,Map<String,Object>> entry : dataSource.entrySet()) {
            String key = entry.getKey();
            String driveType = DriverType.getDriverType(dataSource.get(key).get(YmlConstants.DRIVER_CLASS));
            dataSource.get(key).put("validationQuery", DriverType.getInitSql(driveType));

            keysMap.put(key,driveType);
            /** myDS.put(key,transactionChooseFactory.chooseTransactionDatasource(pubTransaction,key,entry.getValue()));*/
            myDS.put(key,transactionChooseFactory.seataTransaction(entry.getValue()));
        }

        this.dataSourceKeys = keysMap;
        this.dataSources = myDS;
    }



    /** 获取datasource下直接写url原生态的单数据库写法;*/
    private Map<String,Object> getOriginalDataSource(Map<String,Object> defaultDataSourceConfig,Map<String,Object> pubDruidConfig){
        Map<String,Object> newMap = new HashMap<>();
        if ((defaultDataSourceConfig.containsKey(YmlConstants.URL)||defaultDataSourceConfig.containsKey(YmlConstants.JDBC_URL))
                &&defaultDataSourceConfig.containsKey(YmlConstants.USER_NAME)){
            for (Map.Entry<String,Object> entry : pubDruidConfig.entrySet()) {
                String key = entry.getKey();
                newMap.put(key,entry.getValue());
            }
            String url = null;
            if(defaultDataSourceConfig.containsKey(YmlConstants.URL)){
                url = ObjectUtils.toString(defaultDataSourceConfig.get(YmlConstants.URL));
            }
            if(defaultDataSourceConfig.containsKey(YmlConstants.JDBC_URL)){
                url = ObjectUtils.toString(defaultDataSourceConfig.get(YmlConstants.JDBC_URL));
            }
            String driverClass = null;
            if (defaultDataSourceConfig.containsKey(YmlConstants.DRIVER_CLASS)){
                driverClass = ObjectUtils.toString(defaultDataSourceConfig.get(YmlConstants.DRIVER_CLASS));
            }
            if(defaultDataSourceConfig.containsKey(YmlConstants.DRIVER_CLASS_NAME)){
                driverClass = ObjectUtils.toString(defaultDataSourceConfig.get(YmlConstants.DRIVER_CLASS_NAME));
            }
            if(Objects.isNull(driverClass)) {
                driverClass = DriverType.getDriverClass(url);
            }
            String username = ObjectUtils.toString(defaultDataSourceConfig.get(YmlConstants.USER_NAME));
            String password = ObjectUtils.toString(defaultDataSourceConfig.get(YmlConstants.PASSWORD));
            newMap.put(YmlConstants.NAME,YmlConstants.ORIGINAL);
            newMap.put(YmlConstants.JDBC_URL,url);
            newMap.put(YmlConstants.DRIVER_CLASS,driverClass);
            newMap.put(YmlConstants.USER_NAME,username);
            newMap.put(YmlConstants.PASSWORD,password);
        }
        return newMap;
    }
    //获取默认sys以及其他的数据库配置
    private Map<String,Object> getDSConfig(Map<String,Object> defaultDataSourceConfig,String dsName,Map<String,Object> defaultDruidConfig){
        Map<String,Object> map = new HashMap<>();
        map.put(YmlConstants.NAME,dsName);
        for (Map.Entry<String,Object> entry : defaultDruidConfig.entrySet()) {
            String key = entry.getKey();
            map.put(key,entry.getValue());
        }
        Map<String,Object> dsMap = null;
        if (YmlConstants.SYS.equals(dsName)){
            dsMap = DataDefaultConstants.sysDB();
        }else {
            dsMap = (Map<String, Object>) defaultDataSourceConfig.get(dsName);
        }
        if (dsMap.containsKey(YmlConstants.DRUID)){
            Map<String,Object> minDruid = (Map<String,Object>)dsMap.get(YmlConstants.DRUID);
            for (Map.Entry<String,Object> entry : minDruid.entrySet()) {
                String k = entry.getKey();
                map.put(k,entry.getValue());
            }
        }
        for (Map.Entry<String,Object> entry : dsMap.entrySet()) {
            String key = entry.getKey();
            if (key.equals(YmlConstants.URL)||key.equals(YmlConstants.JDBC_URL)){
                map.put(YmlConstants.JDBC_URL,entry.getValue());
                map.put(YmlConstants.DRIVER_CLASS, DriverType.getDriverClass(String.valueOf(entry.getValue()) ));
            } else if(key.equals(YmlConstants.DRIVER_CLASS_NAME)){
                map.put(YmlConstants.DRIVER_CLASS,entry.getValue());
            } else{
                map.put(key,entry.getValue());
            }
        }

        return map;
    }

}
